Previous Book Contents Book Index Next

Inside Macintosh: Programming With JManager /
Chapter 1 - Using JManager


Handling Events

Although the Java applet runs within its own runtime environment, it must often interact with events that occur in the Mac OS. For example, user events (such as mouse clicks) or system events may require some response from the Java program. This section describes JManager functions for handling such events. For more information about how the Mac OS handles events, see "Event Manager" in Inside Macintosh: Macintosh Toolbox Essentials.

Actions performed on a frame may need to be reflected on the user-visible window as well, but in most cases, such actions are handled by JManager through a callback. For example, if the user clicks on an applet window's close box, your application must notify the frame that this has occurred. The Java program can then take action based upon this event, such as removing the frame or displaying a message in a dialog box. In either case, the AWT uses the callback functions you defined in your application to display the results. Figure 1-4 shows the steps for removing an applet window.

Figure 1-4 Removing an applet window

See "Displaying Frames" for more information about using the callbacks.

When an event occurs, you typically call an event-handling function from your main loop. Listing 1-12 shows an example of an event-handling function.

Listing 1-12 Handling events

static void handleEvent(const EventRecord* eve)
{
   switch (eve->what) {

      case updateEvt:
         handleUpdate((WindowPtr) eve->message);
         break;
         
      case activateEvt:
         handleActivate((eve->modifiers & activeFlag) != 0,
            (WindowPtr) eve->message);
         break;

      case osEvt:
         /* everyone should care about this */
         handleResume((eve->message & resumeFlag) != 0);
         break;

      case kHighLevelEvent:
         AEProcessAppleEvent(eve);
         break;

      case mouseDown:
         handleMouse(eve);
         break;

      /* assume no one cares about these */
      case mouseUp:
         break;

      case keyDown:
      case autoKey:
      case keyUp:
         handleKey(eve);
         break;
   }

}
High-level events (generally Apple events) are handled by calling the Mac OS Toolbox function AEProcessAppleEvent. In other cases, the handling functions should check to see if the event needs to be passed to the embedded Java program. The sections that follow describe the JManager functions needed to pass events and give sample implementations of the handleUpdate, handleActivate, handleResume, handleMouse, and handleKey functions.

Update, Activate, and Resume Events

If the application receives an update event, it must update the currently active window. If the window corresponds to a frame, you must pass the update event to the frame using the JMFrameUpdate function. The AWT context can then update the actual window using a callback. Listing 1-13 shows an example of an update function.

Listing 1-13 Handling a frame update event

static void handleUpdate(WindowPtr win)
{
   JMFrameRef frame;
   BeginUpdate(win);
   SetPort(win);
   frame = (JMFrameRef) GetWRefCon(win);
   if (frame)
      JMFrameUpdate(frame, win->visRgn);
   else
      EraseRgn(win->visRgn);
   EndUpdate(win);
}
If an activate event occurs, then a window was made active (that is, brought to the front), and if that window is associated with a frame, you must activate the frame using the JMFrameActivate function. This action gives the frame the opportunity to highlight title bars, scroll bars, and so on. Activating a frame also installs the menu bar associated with the frame. Listing 1-14 gives an example of activating a frame.

Listing 1-14 Sending an activate event to a frame

static void handleActivate(Boolean active, WindowPtr window)
{
   JMFrameRef frame = (JMFrameRef) GetWRefCon(window);
   if (frame)
      JMFrameActivate(frame, active);
}
Note
The JMFrameActivate function can either activate or deactivate a frame, depending on the Boolean value passed to it (the value of active in this example).
Suspend and resume events can also occur when a window is activated or deactivated. When the user switches from one application to another, the newly selected application is sent a resume event, and the previously active one is sent a suspend event. This event affects all the applets embedded within an application, so you must call the JMFrameResume function to suspend or resume all the existing frames.

Listing 1-15 shows how to send a resume event to all the frames associated with a client application.

Listing 1-15 Sending a resume event to frames

static void handleResume(Boolean resume)
{
   WindowPtr win = FrontWindow();
   while (win) {
      JMFrameRef frame = (JMFrameRef) GetWRefCon(win);
      if (frame)
         JMFrameResume(frame, resume);
      win = (WindowPtr) ((WindowPeek) win)->nextWindow;
   }
}
Note
The JMFrameResume function can either suspend or resume a frame, depending on the Boolean value passed to it (the value of resume in this example).
This example cycles through all the visible windows used by the application and sends the event to those associated with frames. However, this example only works if every frame is associated with a window. If this is not the case, you must use some other method to send the resume event.

Mouse Events

A mouse event occurs when you click somewhere in the visible screen area. A function that handles mouse events must check the location of the mouse click and take action as appropriate. If the mouse event took place in a window that corresponds to a frame, you must pass the event to the frame so the Java applet can take proper action.

Listing 1-16 shows a function, handleMouse, that handles a mouse event.

Listing 1-16 Handling a mouse event

void handleMouse(const EventRecord* eve)
{
   WindowPtr win;
   short part = FindWindow(eve->where, &win);

   switch (part) {
      case inMenuBar: {
         long mResult = MenuSelect(eve->where);
         if (mResult != 0)
            menuHit(mResult >> 16, mResult & 0xffff);
      }  break;

       case inDesk:
         break;

       case inSysWindow:
         SystemClick(eve, win);
         break;

       case inContent:
         if (win != FrontWindow())
            SelectWindow(win);
         else {
            JMFrameRef frame = (JMFrameRef) GetWRefCon(win);
            if (frame) {
               /* convert the mouse position to window local */
               /* coordinates and pass it into the Java */
               /* environment */
               Point localPos = eve->where;
               SetPort(win);
               GlobalToLocal(&localPos);
               JMFrameClick(frame, localPos, eve->modifiers);
            }
         }
         break;

       case inDrag: {
         Rect r = (**GetGrayRgn()).rgnBBox;
         DragWindow(win, eve->where, &r);
      }  break;

       case inGoAway: {
         /* request that the frame go away--it will call to the */
         /* frame through a callback if it actually does */
         JMFrameRef frame = (JMFrameRef) GetWRefCon(win);
         if (frame)
            JMFrameGoAway(frame);
          } break;
      
       case inGrow: {
         union GrowResults {
            Point asPt;
            long asLong;
         } results;
         
         JMFrameRef frame = (JMFrameRef) GetWRefCon(win);
         Rect rGrow = { 30, 30, 5000, 5000 };
         results.asLong = GrowWindow(win, eve->where, &rGrow);
         if (frame != nil && results.asLong != 0) {
            /* request that the frame resize itself--it will call */
            /* to the frame through a callback if it actually does */
            Rect r;
            r.left = 0;
            r.top = 0;
            r.right = results.asPt.h;
            r.bottom = results.asPt.v;
            r.bottom -= 15;
            JMSetFrameSize(frame, &r);
            }
         } break;

       default:
         break;
   }
}
This example uses the Mac OS Toolbox function FindWindow to determine the location of the mouse click and then takes action depending on the location.

The inMenuBar, inDesk, and inSysWindow cases are handled as in any Mac OS application.

If the mouse click occurs in a window's content area (inContent), handleMouse checks to see if the window is active. If not, the window is selected (it receives an activate event and possibly a resume event). If the window is currently active, the local position of the mouse within the window is calculated and the coordinates sent to the corresponding frame using the JMFrameClick function. In a similar manner, you can also send a mouse-over event by calling the JMFrameMouseOver function before the JMIdle call in the main event loop.

If the mouse click is in the drag region (inDrag), the Mac OS Toolbox function DragWindow is called to move the window. You do not have to pass any information to the corresponding frame, since the Java runtime environment does not worry about the relative position of frames.

If the mouse click is on the close box (inGoAway), the code notifies the corresponding frame using the JMFrameGoAway function. Any user-visible response to this action (such as removing the window) is handled by the AWT using the callbacks you specified when instantiating the AWT context.

If the mouse click is in a window's size box (inGrow), the code calls the Mac OS Toolbox function GrowWindow to track the new size of the window. The new dimensions are passed to the frame using the JMSetFrameSize function. The dimensions of the window are updated using an AWT context callback.

Note
If the new window dimensions are too large or too small (because of screen constraints or some arbitrary limit), the window should be adjusted to a preferred size.

Keyboard Events

Keyboard events occur whenever the user presses a key. These keypresses may correspond to text entered into a window, a keyboard-equivalent menu selection, or a similar action (for example, selecting the default button in a dialog box by pressing the return key). If the keyboard event occurs in a window that corresponds to a frame, you must pass the event to the frame using either the JMFrameKey function for key-down events or the JMFrameKeyRelease function for key-up events.

Listing 1-17 shows a simple example that handles a keyboard event.

Listing 1-17 Handling a keyboard event

static void handleKey(const EventRecord* eve)
{
   WindowPtr win;
   JMFrameRef frame;
   
   /* see if a menu item was selected */
   if (eve->what == keyDown && (eve->modifiers & cmdKey) == cmdKey) {
      long menuResult = MenuKey(eve->message & charCodeMask);
      if (menuResult != 0) {
         menuHit(menuResult >> 16, menuResult & 0xffff);
         return;
      }
   }
   /* otherwise, just let JManager deal with it */
   win = FrontWindow();
   if (win) {
      frame = (JMFrameRef) GetWRefCon(win);
      if (frame)
         JMFrameKey(frame, eve->message & charCodeMask, 
            (eve->message & keyCodeMask) >> 8, eve->modifiers);
   }
}
This code first checks to see if the keyboard input was a keyboard equivalent for a menu item (for example, Command-Q for Quit). If so, control passes to the menu-event routine (see Listing 1-18 for an example of handling a menu selection). In all other cases, the keyboard input is passed to the frame corresponding to the window, and the Java program can then determine the appropriate response. The content of the keyboard input is determined from the event record (the EventRecord structure) returned by the Event Manager.

Menu Selections

Both mouse events and keyboard events can select menu items. In either case, the event should be handled by a menu selection function. If the selection corresponds to a Java applet's menu item, you must pass the selection to the applet's AWT context using the JMMenuSelected function. Listing 1-18 shows a simple menu selection function.

Listing 1-18 Handling a menu item selection

/* enumerators to define the Mac OS menus*/
enum Menus {
   eAppleMenu = 1000,
   eFileMenu,
   eEditMenu,
   eLastMenu
   };

/* enumerators to define the menu items */
enum AppleMenuItems {
   eAboutItem = 1
   };

enum FileMenuItems {
   eMyAction1 = 1,/* nonstandard menu item defined by */
                  /* the application */
   eQuitItem = eMyAction1 + 2
   };

enum EditMenuItems {
   eUndoItem = 1,
   eCutItem = eUndoItem + 2,
   eCopyItem,
   ePasteItem,
   eClearItem,
   eSelectAllItem = eClearItem + 2
   };

static void menuHit(short menuID, short menuItem)
{
   switch (menuID) {
      case eAppleMenu:
         switch (menuItem) {
            case eAboutItem: /* show About box */
               MyAboutBox();
               break;
               
            default: {  /* open the appropriate desk accessory */
               Str255 s;
               SetPort(LMGetWMgrPort());
               GetItem(GetMHandle(eAppleMenu), menuItem, s);
               if (s[0] > 0)
                  OpenDeskAcc(s);
            }  break;
         }
         break;
         
      case eFileMenu:
         switch (menuItem) {
            case eMyAction1:
               DoMyAction1();
               break;
               
            case eQuitItem:
               MainEventLoopContinues = false;
               break;
         }
         break;
         
      case eEditMenu:
         break;
            
      default: {
         /* pass the menu hit to the AWTContext for processing */
         WindowPtr win = FrontWindow();
         if (win != nil) {
            JMFrameRef frame = (JMFrameRef) GetWRefCon(win);
            if (frame != nil) {
               JMAWTContextRef context = JMGetFrameContext(frame);
               if (context != nil)
                  JMMenuSelected(context, GetMHandle(menuID), 
                     menuItem);
            }
         }
      }  break;
   }
   
   HiliteMenu(0);
}
If the user did not select a standard menu item, the menuHit function passes the menu selection to the applet's AWT context. On the Mac OS, the menu bar is always associated with the active window (and, consequently, with the active frame). After determining the frame associated with the window (using the Mac OS Toolbox function GetWRefCon), JMGetFrameContext returns the AWT context associated with the frame. The menu handle of the selection is then passed to the AWT context using the JMMenuSelected function.

Drag-And-Drop Support

If your embedding application supports the Drag Manager, you can pass drag-and-drop information to a frame using JManager functions. The JMFrameDragTracking function allows your frame to respond to an item dragged over it (for example, creating a highlight to signal that the drag item is valid for the frame). If the user drops the item within the frame boundaries, the JMFrameDragReceive function lets you pass information about the dropped item to the frame.

These functions correspond respectively to the application-defined Drag Manager functions DragTrackingHandler and DragReceiveHandler, and are called from within these handlers. For more information about the Drag Manager, see the Drag Manager Programmer's Guide.

Note
The Java JDK standards 1.1.x and earlier do not support drag and drop.

Subtopics
Update, Activate, and Resume Events
Mouse Events
Keyboard Events
Menu Selections
Drag-And-Drop Support

Previous Book Contents Book Index Next

© Apple Computer, Inc.
10 DEC 1997